package com.vhly.appspot.shortenurl;

import com.google.appengine.api.memcache.stdimpl.GCacheFactory;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.appengine.repackaged.com.google.common.util.Base64;
import com.google.appengine.repackaged.com.google.common.util.Base64DecoderException;
import com.vhly.appspot.HttpClient;
import com.vhly.appspot.ResponseData;

import javax.cache.Cache;
import javax.cache.CacheException;
import javax.cache.CacheFactory;
import javax.cache.CacheManager;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.logging.Logger;

/**
 * Created by IntelliJ IDEA.
 * User: vhly[FR]
 * Date: 2010-3-12
 * Time: 17:32:36
 */

/**
 * /su?f=txt&sv=xxx&u=url
 * <p/>
 * sv=xxx xxx
 *
 * @see ShortenUrlServlet#processShortenService(String, String, String)
 */
public class ShortenUrlServlet extends HttpServlet {

    private static Logger log = Logger.getLogger("ShortenUrlServlet");

    private static Cache suCache;

    @Override
    public void init() throws ServletException {
        super.init();
        if (suCache == null) {
            CacheManager chmanager = CacheManager.getInstance();
            try {
                CacheFactory cacheFactory = chmanager.getCacheFactory();
                HashMap props = new HashMap();
                props.put(GCacheFactory.EXPIRATION_DELTA, 86400); // 1 day
                suCache = cacheFactory.createCache(props);
                log.info("Cache init OK");
            } catch (CacheException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void destroy() {
        super.destroy();
        suCache.clear();
        suCache = null;
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        process(request, response);
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        process(request, response);
    }

    /**
     * 处理请求，返回用户使用的 shorten url
     *
     * @param request  请求
     * @param response 响应
     * @throws ServletException 异常
     * @throws IOException      异常
     */
    private void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO 处理请求
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");

        // cache key
        String requestURI = null;
        String method = request.getMethod();
        String ac = request.getParameter("ac");
        if (ac != null && ac.length() > 0) {
            if (ac.equals("clear")) {

            }
        } else {
            String format = request.getParameter("f");
            String service = request.getParameter("sv");
            String longurl = request.getParameter("u");
            String eu = request.getParameter("eu");
            if (longurl == null || longurl.length() == 0) {
                log.info("longurl is empty");
                if (eu != null && eu.length() > 0) {
                    log.info("eu is " + eu);
                    byte[] buf = null;
                    try {
                        buf = Base64.decode(eu);
                        longurl = new String(buf, "UTF-8");
                        log.info("long is " + longurl);
                    } catch (Base64DecoderException e) {
                        e.printStackTrace();
                    }
                }
            }
            if (longurl != null && longurl.length() > 0) {
                log.info("long to short");
                if (method.equals("GET")) {
                    requestURI = request.getQueryString();
                    log.info(requestURI);
                } else {
                    requestURI = service + format + longurl;
                }
                ResponseData rd = null;
                if (suCache.containsKey(requestURI)) {
                    rd = (ResponseData) suCache.get(requestURI);
                    log.info("has cache");
                } else {
                    log.info("No Cache");
                    rd = processShortenService(service, format, longurl);
                }

                if (rd != null) {
                    response.setStatus(rd.stateCode);
                    if (rd.contentType != null) {
                        response.setContentType(rd.contentType);
                    }
                    if (rd.contentEncoding != null) {
                        response.setHeader("Content-Encoding", rd.contentEncoding);
                    }
                    if (rd.data != null) {
                        response.setContentLength(rd.data.length);
                        ServletOutputStream out = response.getOutputStream();
                        out.write(rd.data);
                        out.close();
                    }
                    if (rd.stateCode == HttpServletResponse.SC_OK) {
                        suCache.put(requestURI, rd);
                    }
                    rd.dealloc();
                }
            } else {
                // TODO 无参数的情况，显示API接口
                response.setStatus(HttpServletResponse.SC_OK);
                PrintWriter pw = response.getWriter();
                response.setContentType("text/html");
                pw.print("<html><head><title>Shorten URL Proxy</title></head><body>");
                pw.print("Shorten URL Service Prxoy 1.0<br />");
                pw.print("  by vhly[FR]<br />");
                pw.print("<br />");
                pw.print("API Induction<br /><br />");
                pw.print("EndPoint: /su<br />");
                pw.print("Parameters:<br />");
                pw.print("sv : Shorten URL Services.<br />");
                pw.print("<ol>");
                pw.print("<li>isgd : is.gd service</li>");
                pw.print("<li>307 : 307.to service</li>");
                pw.print("<li>cligs : cli.gs service</li>");
                pw.print("<li>toly : to.ly service</li>");
                pw.print("<li>bit : bit.ly service</li>");
                pw.print("</ol><br />");
                pw.print("f : format , this paramter is not same for every service, for example to.ly support json buy 307 not.<br />");
                pw.print("<ol><li>txt</li><li>xml</li><li>json</li></ol><br />");
                pw.print("u : long url, should encoded by URLEncoding, some browser support encode by Address bar.<br />");
                pw.print("</body></html>");
                pw.close();
            }
        }
    }

    /**
     * @param service
     * @param format  support xml, txt, json
     * @param longurl
     * @return
     */
    private ResponseData processShortenService(String service, String format, String longurl) {
        ResponseData rd = null;
        String targetURL;
        String eu = null;
        try {
            eu = URLEncoder.encode(longurl, "UTF-8");
            if (service == null || service.length() == 0) {
                service = "isgd";
            }
            if (format == null || format.length() == 0) {
                format = "txt";
            }
            log.info("Process Shorten URL: " + eu + " via " + service + " format: " + format);
            if (service.equals("isgd")) {
                targetURL = "http://is.gd/api.php?longurl=" + eu;
            } else if (service.equals("307")) {
                if (format.equals("txt")) {
                    format = "text";
                } else if (format.equals("xml")) {
                    format = "text";
                }
                targetURL = " http://a.307.to/api2/post?format=" + format + "&u=" + eu;
            } else if (service.equals("cligs")) {
                targetURL = "http://cli.gs/api/v1/cligs/create?key=8f665e86b9e563cf4a9df9707753317c&appid=ShortenURLServlet&url=" + eu;
            } else if (service.equals("toly")) {
                if (format.equals("json")) {
                    targetURL = "http://to.ly/api.php?json=1&longurl=" + eu;
                } else {
                    targetURL = "http://to.ly/api.php?longurl=" + eu;
                }
            } else if (service.equals("xr")) {
                targetURL = "http://api.xr.com/api?link=" + eu;
                // this service will add a Frame
            } else if (service.equals("bit")) {
                targetURL = "http://api.bit.ly/v3/shorten?format=" + format + "&login=vhly&apiKey=R_00679e388e7a17800381323ad5a36f0b&longUrl=" + eu;
            } else {
                targetURL = "http://is.gd/api.php?longurl=" + eu;
            }
            rd = HttpClient.request(targetURL, null, null);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
        return rd;
    }

    public void clearCache(HttpServletResponse response) {
        UserService service = UserServiceFactory.getUserService();
        User user = service.getCurrentUser();
        if (user != null) {
            String em = user.getEmail();
            if (em.equals("avfinder@gmail.com")) {
                suCache.clear();
            } else {
                try {
                    response.sendRedirect(service.createLoginURL("/su?ac=clear"));
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        } else {
            try {
                response.sendRedirect(service.createLoginURL("/su?ac=clear"));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
